package com.content.scaffold.common.mybatis.query;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.content.scaffold.common.annotation.QueryField;
import com.content.scaffold.common.annotation.SensitiveField;
import com.content.scaffold.common.exception.BaseException;
import com.content.scaffold.common.utils.SensitiveFieldEncryptor;
import com.content.scaffold.common.utils.SpringContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Component
public class QueryFieldWrapperUtil  {

    // 字段名到列名的缓存
    private static final Map<String, String> COLUMN_NAME_CACHE = new ConcurrentHashMap<>();

    // 敏感字段缓存
    private static final Map<Class<?>, Map<String, SensitiveField>> SENSITIVE_FIELD_CACHE = new ConcurrentHashMap<>();




    /**
     * 构建QueryWrapper查询条件
     * @param queryEntity 查询条件实体
     * @param <T> 实体类型
     * @return QueryWrapper实例
     */
    public static <T> QueryWrapper<T> build(T queryEntity) {
        if (queryEntity == null) return new QueryWrapper<>();

        Class<T> entityClass = (Class<T>) queryEntity.getClass();
        return build(queryEntity, entityClass);
    }

    /**
     * 构建QueryWrapper查询条件
     * @param queryEntity 查询条件实体
     * @param entityClass 返回的实体类型
     * @param <T> 实体类型
     * @param <Q> 查询条件类型
     * @return QueryWrapper实例
     */
    public static <T, Q> QueryWrapper<T> build(Q queryEntity, Class<T> entityClass) {
        if (queryEntity == null) {
            QueryWrapper<T> wrapper = new QueryWrapper<>();
            wrapper.setEntityClass(entityClass);
            return wrapper;
        }

        return doBuild(queryEntity, entityClass);
    }

    /**
     * 实际构建QueryWrapper的私有方法
     * @param queryEntity 查询条件实体
     * @param entityClass 返回的实体类型
     * @param <T> 实体类型
     * @param <Q> 查询条件类型
     * @return QueryWrapper实例
     */
    private static <T, Q> QueryWrapper<T> doBuild(Q queryEntity, Class<T> entityClass) {
        Class<Q> queryClass = (Class<Q>) queryEntity.getClass();
        Field[] allFields = queryClass.getDeclaredFields();
        List<QueryCondition> conditionList = new ArrayList<>();

        // 遍历所有字段
        for (Field field : allFields) {
            // 过滤Lambda生成的匿名字段
            if (field.getName().startsWith("lambda$")) {
                continue;
            }
            QueryCondition condition = parseFieldToCondition(queryEntity, field, entityClass);
            if (condition != null) {
                conditionList.add(condition);
            }
        }

        // 处理分组并构建Wrapper
        QueryWrapper<T> wrapper = new QueryWrapper<>();
        wrapper.setEntityClass(entityClass);
        handleGroupAndBuildWrapper(wrapper, conditionList);
        return wrapper;
    }

    /**
     * 解析单个字段为查询条件
     */
    private static <T, Q> QueryCondition parseFieldToCondition(Q queryEntity, Field field, Class<T> entityClass) {
        try {
            field.setAccessible(true);
            Object fieldValue = field.get(queryEntity);
            String fieldName = field.getName();

            // 过滤无效值
            if (fieldValue == null || isEmptyCollection(fieldValue)) {
                return null;
            }

            QueryCondition condition = new QueryCondition();
            if (field.isAnnotationPresent(QueryField.class)) {
                // 带注解：按注解配置填充条件
                QueryField queryField = field.getAnnotation(QueryField.class);
                fillConditionByAnnotation(condition, queryField, entityClass, field, fieldValue);
            } else {
                // 无注解：按默认规则填充条件（EQ查询）
                fillConditionByDefault(condition, entityClass, fieldName, fieldValue);
            }

            // 处理敏感字段加密
            handleSensitiveFieldEncryption(condition, entityClass, field, fieldValue);

            return condition;

        } catch (Exception e) {
            throw new RuntimeException("解析字段[" + field.getName() + "]失败", e);
        }
    }

    /**
     * 处理敏感字段加密
     */
    private static <T> void handleSensitiveFieldEncryption(
            QueryCondition condition, Class<T> entityClass, Field field, Object fieldValue) {
        if (!(fieldValue instanceof String) || fieldValue.toString().isEmpty()) {
            return;
        }

        // 检查目标实体类中的对应字段是否为敏感字段
        SensitiveField sensitiveField = getSensitiveField(entityClass, field.getName());
        if (sensitiveField != null && sensitiveField.encryption()) {
            // 对查询值进行加密
            try {
                String encryptedValue = SensitiveFieldEncryptor.getAesInstance().encryptHex(fieldValue.toString());
                condition.setValue(encryptedValue);
            } catch (Exception e) {
                throw new RuntimeException("加密字段[" + field.getName() + "]失败", e);
            }
        }
    }

    /**
     * 获取实体类中的敏感字段注解
     */
    private static <T> SensitiveField getSensitiveField(Class<T> entityClass, String fieldName) {
        Map<String, SensitiveField> sensitiveFields = SENSITIVE_FIELD_CACHE.computeIfAbsent(
                entityClass, cls -> {
                    Map<String, SensitiveField> fieldMap = new HashMap<>();
                    Class<?> clazz = cls;
                    while (clazz != null && clazz != Object.class) {
                        for (Field f : clazz.getDeclaredFields()) {
                            SensitiveField annotation = f.getAnnotation(SensitiveField.class);
                            if (annotation != null) {
                                fieldMap.put(f.getName(), annotation);
                            }
                        }
                        clazz = clazz.getSuperclass();
                    }
                    return fieldMap;
                });

        return sensitiveFields.get(fieldName);
    }

    /**
     * 带@QueryField注解的字段：按注解配置填充条件
     */
    private static <T> void fillConditionByAnnotation(
            QueryCondition condition, QueryField queryField,
            Class<T> entityClass, Field field, Object fieldValue) {

        // 子查询处理
        Object finalValue = queryField.subQuery() ?
                executeSubQuery(queryField, fieldValue) :
                processDateValue(field, fieldValue, queryField.dateFill());

        condition.setLogic(queryField.logic())
                .setGroupKey(queryField.groupKey().trim())
                .setQueryType(queryField.type())
                .setCustomSql(queryField.customSql().trim())
                .setFieldName(getColumnName(entityClass, field.getName())) // 使用数据库列名
                .setValue(finalValue);
    }

    /**
     * 无@QueryField注解的字段：按默认规则填充（EQ查询）
     */
    private static <T> void fillConditionByDefault(
            QueryCondition condition, Class<T> entityClass,
            String fieldName, Object fieldValue) {

        condition.setLogic(QueryField.LogicType.AND)
                .setGroupKey("")
                .setQueryType(QueryField.QueryType.EQ)
                .setCustomSql("")
                .setFieldName(getColumnName(entityClass, fieldName)) // 使用数据库列名
                .setValue(fieldValue);
    }

    /**
     * 获取数据库列名
     */
    private static <T> String getColumnName(Class<T> entityClass, String fieldName) {
        String cacheKey = entityClass.getName() + "." + fieldName;
        return COLUMN_NAME_CACHE.computeIfAbsent(cacheKey, k -> {
            try {
                Field field = getField(entityClass, fieldName);
                if (field == null) {
                    return camelToUnderline(fieldName);
                }

                // 检查 @TableField 注解
                if (field.isAnnotationPresent(TableField.class)) {
                    TableField tableField = field.getAnnotation(TableField.class);
                    if (StringUtils.hasText(tableField.value())) {
                        return tableField.value();
                    }
                }

                // 检查 @TableId 注解
                if (field.isAnnotationPresent(TableId.class)) {
                    TableId tableId = field.getAnnotation(TableId.class);
                    if (StringUtils.hasText(tableId.value())) {
                        return tableId.value();
                    }
                }

                // 默认使用驼峰转下划线
                return camelToUnderline(fieldName);
            } catch (Exception e) {
                return fieldName;
            }
        });
    }

    /**
     * 获取字段（包括父类字段）
     */
    private static <T> Field getField(Class<T> entityClass, String fieldName) {
        Class<?> clazz = entityClass;
        while (clazz != Object.class) {
            try {
                return clazz.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
                clazz = clazz.getSuperclass();
            }
        }
        return null;
    }

    /**
     * 驼峰命名转下划线命名
     */
    private static String camelToUnderline(String camelCase) {
        if (!StringUtils.hasText(camelCase)) {
            return "";
        }
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < camelCase.length(); i++) {
            char c = camelCase.charAt(i);
            if (Character.isUpperCase(c)) {
                if (i > 0) {
                    result.append("_");
                }
                result.append(Character.toLowerCase(c));
            } else {
                result.append(c);
            }
        }
        return result.toString();
    }

    /**
     * 执行子查询
     */
    private static Object executeSubQuery(QueryField queryField, Object param) {
        if (queryField.subQueryMapper() == void.class || !BaseMapper.class.isAssignableFrom(queryField.subQueryMapper())) {
            throw new BaseException("子查询注解@QueryField需配置继承BaseMapper的subQueryMapper");
        }
        BaseMapper<?> mapper = (BaseMapper<?>) SpringContextHolder.getBean(queryField.subQueryMapper());
        try {
            Method method = mapper.getClass().getMethod(queryField.subQueryMethod(), Object.class);
            Object result = method.invoke(mapper, param);
            return result instanceof Collection ? result : Collections.singletonList(result);
        } catch (NoSuchMethodException e) {
            throw new BaseException("子查询Mapper[" + queryField.subQueryMapper().getSimpleName() + "]不存在方法[" + queryField.subQueryMethod() + "(Object)]", e);
        } catch (Exception e) {
            throw new BaseException("子查询执行失败：Mapper=" + queryField.subQueryMapper().getSimpleName() + ", Method=" + queryField.subQueryMethod(), e);
        }
    }

    /**
     * 处理日期值
     */
    private static Object processDateValue(Field field, Object value, QueryField.DateFillRule fillRule) {
        if (field.getType() != LocalDateTime.class || fillRule == QueryField.DateFillRule.NONE) {
            return value;
        }
        LocalDateTime date = (LocalDateTime) value;
        return fillRule == QueryField.DateFillRule.START_OF_DAY ? date.with(LocalTime.MIN) : date.with(LocalTime.MAX);
    }

    /**
     * 处理分组并构建查询条件
     */
    private static <T> void handleGroupAndBuildWrapper(QueryWrapper<T> wrapper, List<QueryCondition> conditionList) {
        if (conditionList.isEmpty()) return;

        // 按分组key分组
        Map<String, List<QueryCondition>> groupMap = conditionList.stream()
                .collect(Collectors.groupingBy(QueryCondition::getGroupKey, LinkedHashMap::new, Collectors.toList()));

        boolean isFirstGroup = true;
        for (Map.Entry<String, List<QueryCondition>> entry : groupMap.entrySet()) {
            String groupKey = entry.getKey();
            List<QueryCondition> groupConditions = entry.getValue();

            // 过滤掉无效条件
            List<QueryCondition> validConditions = groupConditions.stream()
                    .filter(condition -> condition.getValue() != null && !isEmptyCollection(condition.getValue()))
                    .collect(Collectors.toList());

            if (validConditions.isEmpty()) {
                continue;
            }

            // 非第一个分组：添加分组间的逻辑
            if (!isFirstGroup) {
                QueryField.LogicType logicType = validConditions.get(0).getLogic();
                if (logicType == QueryField.LogicType.AND) {
                    if (!groupKey.isEmpty()) {
                        wrapper.and(w -> buildGroupWrapper(w, validConditions));
                    } else {
                        buildGroupWrapper(wrapper, validConditions);
                    }
                } else {
                    if (!groupKey.isEmpty()) {
                        wrapper.or(w -> buildGroupWrapper(w, validConditions));
                    } else {
                        buildGroupWrapper(wrapper, validConditions);
                    }
                }
            } else {
                // 第一个分组直接添加
                if (!groupKey.isEmpty()) {
                    wrapper.and(w -> buildGroupWrapper(w, validConditions));
                } else {
                    buildGroupWrapper(wrapper, validConditions);
                }
            }
            isFirstGroup = false;
        }
    }

    /**
     * 构建分组查询条件
     */
    private static <T> void buildGroupWrapper(QueryWrapper<T> wrapper, List<QueryCondition> groupConditions) {
        for (int i = 0; i < groupConditions.size(); i++) {
            QueryCondition condition = groupConditions.get(i);
            executeCondition(wrapper, condition);
        }
    }

    /**
     * 执行具体的查询条件
     */
    private static <T> void executeCondition(QueryWrapper<T> wrapper, QueryCondition condition) {
        String customSql = condition.getCustomSql();
        if (!customSql.isEmpty()) {
            wrapper.apply(customSql.replace("#{val}", "?"), condition.getValue());
            return;
        }

        String fieldName = condition.getFieldName();
        Object value = condition.getValue();
        QueryField.QueryType type = condition.getQueryType();

        // IN/NOT_IN处理
        if (type == QueryField.QueryType.IN || type == QueryField.QueryType.NOT_IN) {
            List<?> valueList = value instanceof Collection ? (List<?>) value : Collections.singletonList(value);
            if (type == QueryField.QueryType.IN) {
                wrapper.in(fieldName, valueList);
            } else {
                wrapper.notIn(fieldName, valueList);
            }
            return;
        }

        // 其他查询类型处理
        switch (type) {
            case EQ:
                wrapper.eq(fieldName, value);
                break;
            case NEQ:
                wrapper.ne(fieldName, value);
                break;
            case LIKE:
                wrapper.like(fieldName, value);
                break;
            case LIKE_LEFT:
                wrapper.likeLeft(fieldName, value);
                break;
            case LIKE_RIGHT:
                wrapper.likeRight(fieldName, value);
                break;
            case BETWEEN:
                handleBetween(wrapper, fieldName, value);
                break;
            case GT:
                wrapper.gt(fieldName, value);
                break;
            case LT:
                wrapper.lt(fieldName, value);
                break;
            case GE:
                wrapper.ge(fieldName, value);
                break;
            case LE:
                wrapper.le(fieldName, value);
                break;
            case IS_NULL:
                wrapper.isNull(fieldName);
                break;
            case IS_NOT_NULL:
                wrapper.isNotNull(fieldName);
                break;
            default:
                throw new RuntimeException("不支持的查询类型：" + type);
        }
    }

    /**
     * 处理BETWEEN查询
     */
    private static <T> void handleBetween(QueryWrapper<T> wrapper, String fieldName, Object value) {
        List<?> valueList;
        if (value instanceof Collection) {
            valueList = new ArrayList<>((Collection<?>) value);
        } else if (value.getClass().isArray()) {
            valueList = Arrays.asList((Object[]) value);
        } else {
            throw new RuntimeException("BETWEEN查询需传入集合或数组（包含2个值）");
        }
        if (valueList.size() != 2) {
            throw new RuntimeException("BETWEEN查询需传入2个值，当前：" + valueList.size() + "个");
        }
        wrapper.between(fieldName, valueList.get(0), valueList.get(1));
    }

    /**
     * 判断是否为空集合
     */
    private static boolean isEmptyCollection(Object value) {
        if (value instanceof List) {
            return ((List<?>) value).isEmpty();
        }
        if (value.getClass().isArray()) {
            return ((Object[]) value).length == 0;
        }
        if (value instanceof Collection) {
            return ((Collection<?>) value).isEmpty();
        }
        return false;
    }

    /**
     * 查询条件封装类
     */
    private static class QueryCondition {
        private QueryField.LogicType logic;
        private String groupKey;
        private QueryField.QueryType queryType;
        private String customSql;
        private String fieldName; // 使用字段名替代Lambda表达式
        private Object value;

        // Getters and Setters
        public QueryCondition setLogic(QueryField.LogicType logic) { this.logic = logic; return this; }
        public QueryCondition setGroupKey(String groupKey) { this.groupKey = groupKey; return this; }
        public QueryCondition setQueryType(QueryField.QueryType queryType) { this.queryType = queryType; return this; }
        public QueryCondition setCustomSql(String customSql) { this.customSql = customSql; return this; }
        public QueryCondition setFieldName(String fieldName) { this.fieldName = fieldName; return this; }
        public QueryCondition setValue(Object value) { this.value = value; return this; }

        public QueryField.LogicType getLogic() { return logic; }
        public String getGroupKey() { return groupKey; }
        public QueryField.QueryType getQueryType() { return queryType; }
        public String getCustomSql() { return customSql; }
        public String getFieldName() { return fieldName; }
        public Object getValue() { return value; }
    }
}
